package com.hbnu.system.controller;


import com.hbnu.system.core.base.Rest;
import com.hbnu.system.model.entity.User;
import com.hbnu.system.model.entity.UserInfo;
import com.hbnu.system.service.IUserService;
import com.hbnu.system.utils.JwtUtils;
import lombok.extern.slf4j.Slf4j;
import org.jasig.cas.client.validation.Assertion;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import static com.hbnu.system.core.base.RestCode.NOT_SSO_LOGIN;

/**
 * 前后端分离模式下的CAS单点登录控制器
 */
@RestController
@RequestMapping("/sso")
@Slf4j
public class SSOController {

    @Value("${cas.server-url-prefix}")
    private String serverUrlPrefix;

    @Value("${cas.client-host-url}")
    private String clientHostUrl;

    @Value("${cas.server-login-url}")
    private String casServerUrl;

    @Value("${front.url}")
    private String frontUrl;

    @Value("${back.url}")
    private String serverUrl;

    private static final Logger LOGGER = LoggerFactory.getLogger(SSOController.class);
    /**
     * cas client 默认的session key
     */
    public static final String CAS_ASSERTION_KEY = "_const_cas_assertion_";

    @Autowired
    private IUserService userService;

    /**
     * 获取当前登录用户信息
     */
    @GetMapping("/user-info")
    public Rest getUserInfo(HttpServletRequest request )   {
        UserInfo userInfo = getUserInfoFromCas(request);
        if (userInfo == null) {
            return Rest.failed(NOT_SSO_LOGIN);
        }
        //查找用户信息
        User user = userService.getUserByAccount(userInfo.getUid());
        //构建token返回
        Map<String, String> result = new HashMap<>();
        result.put("token",JwtUtils.getJwtToken(user.getUid(), user.getRole()));
        //构建用户工号
        result.put("username", user.getAccount());
        //构建密码
        return Rest.success(result);
    }


    /**
     * 回调地址
     * @param response
     * @throws IOException
     */
    @GetMapping("/checkTicket")
    public void index(HttpServletRequest request,HttpServletResponse response) throws IOException {
        UserInfo userInfo = getUserInfoFromCas(request);
        log.info("用户信息: {}", userInfo);
        log.info("用户信息: {}", userInfo.getUid());
        //查找用户信息
        User user = userService.getUserByAccount(userInfo.getUid());
        // 前端页面地址
        response.sendRedirect(frontUrl+"?token="+JwtUtils.getJwtToken(user.getUid(), user.getRole()));
    }

    /**
     * 登出接口
     */
    @GetMapping("/logout")
    public void logout(HttpServletRequest request, HttpServletResponse response) throws IOException {
        // 1. 清除本地会话
        request.getSession().invalidate();

        // 2. 构建CAS登出地址，登出后重定向到前端首页
        String logoutUrl = serverUrlPrefix+"/logout?service=" + frontUrl;

        // 3. 重定向到CAS服务器执行全局登出
        response.sendRedirect(logoutUrl);
    }


    /**
     * 从CAS会话中获取用户信息
     */
    private UserInfo getUserInfoFromCas(HttpServletRequest request) {
        Object object = request.getSession().getAttribute(CAS_ASSERTION_KEY);
        if (object == null) {
            LOGGER.warn("未从会话中获取到CAS认证信息");
            return null;
        }

        try {
            Assertion assertion = (Assertion) object;
            return buildUserInfoByCas(assertion);
        } catch (ClassCastException e) {
            LOGGER.error("CAS认证信息类型转换失败", e);
            return null;
        }
    }

    /**
     * 根据CAS断言构建用户信息
     */
    private UserInfo buildUserInfoByCas(Assertion assertion) {
        UserInfo userInfo = new UserInfo();
        String userName = assertion.getPrincipal().getName();
        LOGGER.info("CAS登录用户: {}", userName);

        //用户的工号
        userInfo.setUid(userName);

        return userInfo;
    }
}
